package com.zjc.code.algorithm;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TyporaClean {
    //TODO:1.先确认md文件已保存再运行(或者设置自动保存)，不然检测不到最新图片
    public static void main(String[] args) {

        // 笔记存储根目录
        String noteRootPath;

        // 从命令行读取笔记存储根目录，否则使用默认值
        if (args == null || args.length == 0) {
            // TODO:2.设置笔记存储根目录
            noteRootPath = "D:\\Documents\\大三下\\备战秋招\\笔记\\md笔记";
        } else {
            noteRootPath = args[0];
        }

        // 执行 Typora 瘦身程序
        doClean(noteRootPath);
    }

    /**
     * 执行 Typora 瘦身程序
     *
     * @param destPath 笔记存储根目录
     */
    private static void doClean(String destPath) {

        // 获取当前路径的File对象
        File destPathFile = new File(destPath);

        // 获取当前路径下所有的子文件和路径
        File[] allFiles = destPathFile.listFiles();

        // 遍历allFiles
        for (File curFile : allFiles) {

            // 获取curFile对象是否为文件夹
            Boolean isDirectory = curFile.isDirectory();

            // 如果是文件夹
            if (isDirectory) {

                // 获取当前curFile对象对应的绝对路径名
                String absolutePath = curFile.getAbsolutePath();

                // 如果是asset文件夹，则直接调过
                if (absolutePath.endsWith(".assets")) {
                    continue;
                }

                // 如果是文件夹，则继续执行递归
                doClean(absolutePath);

            } else {

                // 如果是文件，执行单个md文件的图片瘦身
                doSinglePicClean(curFile);

            }
        }
    }

    /**
     * 执行单个md文件的图片瘦身
     *
     * @param curFile MD文件的File对象
     */
    public static void doSinglePicClean(File curFile) {

        // 获取文件名
        String curFileName = curFile.getName();

        // 文件名后缀，我们只处理md文件
        Boolean isMd = curFileName.endsWith(".md");

        // 如果不是md文件，我们不处理
        if (!isMd) {
            return;
        }

        // 存储图片的文件夹名称
        String curFilNameWithoutMd = curFileName.replace(".md", "");
        String curAssetName = curFilNameWithoutMd + ".assets";

        // 创建asset文件夹所对应的file对象
        String curAssetAbsolutePath = curFile.getParent() + "\\" + curAssetName;
        File curAssetFile = new File(curAssetAbsolutePath);

        // 判断 assets文件夹是否存在，
        Boolean iscurAssetExist = curAssetFile.exists();
        // assets文件夹存在才执行清理操作
        if (iscurAssetExist) {

            //asset文件夹存在，则进行瘦身
            CleanUnnecessaryPic(curFile, curAssetFile);

        }
    }

    /**
     * 删除无用图片
     *
     * @param curFile      MD文件的File对象
     * @param curAssetFile MD文件对应的assets目录的File对象
     */
    public static void CleanUnnecessaryPic(File curFile, File curAssetFile) {

        // 获取所有图片的绝对路径
        File[] allPicFiles = curAssetFile.listFiles();

        // 获取md文件中用到的所有图片
        String[] usedPicNames = getUsedPicNames(curFile);

        //对比，并进行删除
        CleanUnusedPic(allPicFiles, usedPicNames);
    }

    /**
     * 取md文件中用到的所有图片
     *
     * @param curFile MD文件的File对象
     * @return
     */
    public static String[] getUsedPicNames(File curFile) {

        // 读取md文件内容
        String mdFileContent = readMdFileContent(curFile);

        // 图片名称
        // 图片路径存储格式：![image-20200603100128164](Typora 瘦身.assets/image-20200603100128164.png)
        /*
            \[.*\]：[image-20200603100128164]
                . ：匹配任意字符
                * ：出现0次或多次
            \(.+\)：(IDEA快捷键.assets/image-20200603100128164.png)
                . ：匹配任意字符
                + ：出现1次或多次
         */
        String regex = "!\\[.*\\]\\(.+\\)";

        // 匹配文章中所有的图片标签
        Matcher matcher = Pattern.compile(regex).matcher(mdFileContent);

        // imageNames 用于存储匹配到的图片标签
        List<String> imageNames = new ArrayList<>();

        //遍历匹配项，将其添加至集合中
        while (matcher.find()) {

            // 得到当前图片标签
            String curImageLabel = matcher.group();

            // 放心大胆地使用"/"截取子串，因为文件名不能包含"/"字符
            Integer picNameStartIndex = curImageLabel.lastIndexOf("/") + 1;
            Integer picNameEndIndex = curImageLabel.length() - 1;
            // 得到图片名称
            String curImageName = curImageLabel.substring(picNameStartIndex, picNameEndIndex);

            // 添加至集合中
            imageNames.add(curImageName);

        }

        // 转换为数组返回
        String[] retStrs = new String[imageNames.size()];
        return imageNames.toArray(retStrs);
    }

    /**
     * 读取MD文件的内容
     *
     * @param curFile MD文件的File对象
     * @return
     */
    public static String readMdFileContent(File curFile) {

        // 存储md文件内容
        StringBuilder sb = new StringBuilder();

        // 当前行内容
        String curLine;

        // 装饰者模式：FileReader无法一行一行读取，所以使用BufferedReader装饰FileReader
        try (
                FileReader fr = new FileReader(curFile);
                BufferedReader br = new BufferedReader(fr);
        ) {
            // 当前行有内容
            while ((curLine = br.readLine()) != null) {
                sb.append(curLine + "\r\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 返回md文件内容
        return sb.toString();
    }

    /**
     * 清除无用的图片
     *
     * @param allPicFiles  所有本地图片的File对象数组
     * @param usedPicNames MD文件中使用到的图片名称数组
     */
    private static void CleanUnusedPic(File[] allPicFiles, String[] usedPicNames) {

        // assets文件夹中如果没有图片，则直接返回
        if (allPicFiles == null || allPicFiles.length == 0) {
            return;
        }

        // 获取asset文件夹的绝对路径
        String assetPath = allPicFiles[0].getParent();

        // 为了便于操作，将数组转换为List
        List<String> usedPicNameList = Arrays.asList(usedPicNames);

        // 遍历所有本地图片，看看有哪些图片没有被使用
        for (File curPicFile : allPicFiles) {

            // 如果没有被使用，则添加至unusedPicNames集合
            String curFileName = curPicFile.getName();
            boolean isUsed = usedPicNameList.contains(curFileName);
            if (!isUsed) {
                // 创建File对象，用于删除
                String curPicAbsolutePath = curPicFile.getAbsolutePath();

                // 测试用：打印输出
                System.out.println("已删除无用图片:" + curPicAbsolutePath);

                // 删除文件，看看回收站还有没有，并没有。。。
                curPicFile.delete();
            }

        }

    }

}
